package com.lingjtx.common.security.aop;

import com.lingjtx.common.core.constant.Const;
import com.lingjtx.common.core.constant.ResponseTip;
import com.lingjtx.common.core.exception.ForbiddenException;
import com.lingjtx.common.core.util.StringUtil;
import com.lingjtx.common.security.annotation.Permissions;
import com.lingjtx.common.core.token.UserVo;
import com.lingjtx.common.security.common.DataScope;
import com.lingjtx.common.security.common.DataScopeType;
import com.lingjtx.common.security.common.PermissionType;
import com.lingjtx.common.security.interceptor.UserContext;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Objects;

@Component
@Aspect
@Order(2)
public class PermissionAspect {

    @Before("@annotation(com.lingjtx.common.security.annotation.Permissions)")
    public void interceptor(JoinPoint point) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Permissions annotation = signature.getMethod().getAnnotation(Permissions.class);
        UserVo user = UserContext.getUser();
        if (Objects.nonNull(annotation) && Objects.nonNull(user)) {
            PermissionType[] types = annotation.type();
            for (PermissionType permissionType : types) {
                // 检查按钮权限
                outerLoop:
                // 标记本次循环，用于跳到这里
                if (PermissionType.HAS_PERMISSION.equals(permissionType)) {
                    if (StringUtil.isNotEmpty(user.getPerms())) {
                        for (String perm : user.getPerms()) {
                            if (annotation.value().equals(perm)) {
                                break outerLoop; // 跳出外层循环，同一个列表接口，可能既有按钮权限，又有数据权限
                            }
                        }
                    }
                    throw new ForbiddenException(ResponseTip.RESPONSE_BODY_FORBIDDEN);
                } else {
                    // 处理数据权限范围
                    // 从缓存中查询到该用户具有的角色范围，能访问的数据范围，某个字段（user_id, company_id(部门/组织)）的集合Set
                    // 一般用户登录的时候，就会去查询该用户的所有信息和角色范围，都缓存在UserVo里面

                    // 要明白一点不管开发者账号，B端用户账号还是系统运营账号，数据的归属都属于改公司/组织/部门，而不是属于操作账号
                    // 数据主表都会加上组织/公司ID，多级分销在组织/公司表里加上集合[1,2,3]

                    if (Const.UserType.DEVELOPER.equals(user.getUserType())) { // 开发者账号不做数据权限
                        return;
                    }
                    dataScopeHandle(annotation, user);
                }
            }
        }
    }


    private DataScope dataScopeHandle(Permissions annotation, UserVo user) {
        if (DataScopeType.ALL.getCode().equals(user.getScopeType())) {
            return null;
        }
        DataScope scope = new DataScope();
        if (Const.UserType.TOB.equals(user.getUserType())) {
            scope.setField("company_id");
        }

        if (Const.UserType.SYSTEM.equals(user.getUserType())) {
            scope.setField("dept_id");
        }

        if (Const.UserType.TOC.equals(user.getUserType())) {
            scope.setField("user_id");
        }

        StringBuilder sqlWhere = new StringBuilder();
        if (DataScopeType.ONLY_ME.getCode().equals(user.getScopeType())) {
            scope.setField("create_by");
            scope.setValue(user.getUserId());
            sqlWhere.append(" AND ")
                    .append(annotation.alias())
                    .append(scope.getField())
                    .append("=")
                    .append(scope.getValue());
        }

        if (DataScopeType.ONLY_DEPT.getCode().equals(user.getScopeType())) {
            scope.setValue(user.getCompanyId());
            sqlWhere.append(" AND ")
                    .append(annotation.alias())
                    .append(scope.getField())
                    .append("=")
                    .append(scope.getValue());
        }

        if (DataScopeType.CUSTOM.getCode().equals(user.getScopeType())) {
            if (Objects.nonNull(user.getScopeList()) && !user.getScopeList().isEmpty()) {
                scope.setList(user.getScopeList());
                StringBuilder inStr = new StringBuilder();
                for (Long id : user.getScopeList()) {
                    inStr.append(",").append(id);
                }
                sqlWhere.append(" AND ")
                        .append(annotation.alias())
                        .append(scope.getField())
                        .append(" IN ( ")
                        .append(inStr.substring(1))
                        .append(" ) ");
            }
        }

        // TTL上下文传递
        user.setSqlWhere(sqlWhere.toString());
        UserContext.setUser(user);

        // 我们也可以用aop的环绕通知@Around来修改传递参数Object[] args = joinPoint.getArgs();
        // 默认args最后一个参数对象为DataScope类：在controller接口带上@Permissions(type=PermissionType.HAS_DATA_SCOPE)注解的方法
        // controller接口方法里最后一个参数是 DataScope 即可通过参数修改传递给 service
//        scope.setScopeType(user.getScopeType());
//        scope.setSqlWhere(sqlWhere.toString());
        return scope;
    }
}
